# Sui Owned Object Pools Overview

import { Callout } from 'nextra/components';

<Callout type="warning">
	Sui Owned Object Pools (SuiOOP) will likely be replaced by
	[`ParallelTransactionExecutor`](../executors#paralleltransactionexecutor) from
	`@mysten/sui/transactions`

    Sui Owned Object Pools (SuiOOP) is a beta library. Enhancements and changes are likely during
    development.

</Callout>

Equivocation is a situation where you unintentionally use the same object in more than one
transaction and is a common pitfall for builders using owned objects. Implementing horizontal
scaling or concurrency for a service that executes transactions on Sui in the natural way results in
an architecture that issues multiple transactions in parallel from the same account.

The community largely avoids using owned objects as a result, but doing so means you lose the
benefit of the lower latency those objects provide. On top of that, they are impossible to
completely avoid because the transaction's gas coin is an owned object.

Finally, the situation is exacerbated by
[gas smashing](https://docs.sui.io/concepts/transactions/gas-smashing) and the Sui TypeScript SDK's
default coin selection logic, which uses all the `0x2::coin::Coin<0x2::sui::SUI>` objects owned by
an address for every transaction's gas payment. These defaults make sending transactions from your
wallet straightforward (doing so automatically cleans up coin dust), but means that developers
writing services need to work against the defaults to maintain distinct gas coins to run
transactions in parallel.

This library addresses these issues, simplifying access to owned objects from backend services that
also need to take advantage of concurrency, without equivocating their objects.

## The SuiOOP solution

The main modules of the library are `executorServiceHandler.ts` and `pool.ts`.

- `executorServiceHandler.ts` contains the logic of the executor service - meaning that it acts like
  a load balancer, distributing the transactions to the worker pools.
- `pool.ts` contains the logic of the worker pools.

As a user of the library, you use only the `executorServiceHandler.ts` module.

The basic concept of SuiOOP is to provide a `ExecutorServiceHandler` to use multiple worker pools
contained in a `workersQueue`, where each worker executes one of the transactions the user provides
when calling the `execute` function.

The flow goes as follows:

First, initialize the `ExecutorServiceHandler` containing only one `mainPool`. Then, whenever you
submit a transaction to the `ExecutorServiceHandler`, it tries to find if there is an available
worker pool to sign and execute the transaction.

The main pool is not a worker pool, meaning that it does not execute transactions. It is only used
to store the objects and coins of the account, and to provide them to the worker pools when needed.

If a worker pool is not found, the `ExecutorServiceHandler` creates one by splitting the `mainPool`.
It does this by taking a part of the objects and coins of the `mainPool` and creates a new worker
pool. This is how the `ExecutorServiceHandler` scales up.

You can define the split logic by providing a `SplitStrategy` object to the `ExecutorServiceHandler`
on initialization. If you don't provide a `splitStrategy`, the `DefaultSplitStrategy` is used.

## Example code

As an example, assume that you need to execute 10 transactions that transfer 100 MIST each to a
fixed recipient.

Before you can run this example, you need to already have at least one coin of type
`0x2::coin::Coin<0x2::sui::SUI>` in your wallet for each transaction that you need to execute in
parallel (in our case 10 coins). Each `Coin<SUI>` should have enough balance to execute each
transaction. If you need SUI for a test network, you can
[use a faucet](https://docs.sui.io/guides/developer/getting-started/get-coins) to mint some.

```ts
import { SuiClient } from '@mysten/sui/client';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { Transaction } from '@mysten/sui/transactions';
import { fromBase64 } from '@mysten/sui/utils';

/* HERE ARE DEFINED THE PREPARATORY STEPS IF YOU WANT TO CODE ALONG*/
// Define the transaction
function createPaymenttx(recipient: string): Transaction {
	const tx = new Transaction();
	const [coin] = tx.splitCoins(
		tx.gas,
		[tx.pure(1000000)], // Amount to be transferred to the recipient
	);
	tx.transferObjects([coin], tx.pure(recipient));
	return tx;
}
// Define your admin keypair and client
const ADMIN_SECRET_KEY: string = '<your-address-secret-key>';
const adminPrivateKeyArray = Uint8Array.from(Array.from(fromBase64(ADMIN_SECRET_KEY)));
const adminKeypair = Ed25519Keypair.fromSecretKey(adminPrivateKeyArray.slice(1));

const client = new SuiClient({
	url: process.env.SUI_NODE!,
});
```

Now, set up the service handler and execute the transactions defined previously. Use the `execute`
method of the `ExecutorServiceHandler` class.

```ts
import { ExecutorServiceHandler } from 'suioop';

// Setup the executor service
const eshandler = await ExecutorServiceHandler.initialize(adminKeypair, client);
// Define the number of transactions to execute
const promises = [];
let tx: TransactionBlockWithLambda;
for (let i = 0; i < 10; i++) {
	tx = new TransactionBlockWithLambda(() => ceatePaymenttx('<recipient-address>'));
	promises.push(eshandler.execute(tx, client));
}

// Collect the promise results
const results = await Promise.allSettled(promises);
```

Notice the use of `TransactionBlockWithLambda()` instead of `Transaction()`. The
`TransactionBlockWithLambda` function is a more flexible way of defining transactions. What differs
is that the transaction will be created later, just before the transaction execution is done by a
worker pool.

And that's it! 🚀

## Processing flow

The overall processing flow is depicted in the following flowchart:

![SuiOOP processing flow](/sui-exec-handler-flowchart.png)
